/*
 * Copyright (c) 2008-2009 by JK
 * All rights reserved.
 */
package net.beyond.common.ssh;

import java.sql.SQLException;
import java.util.Collection;
import java.util.List;
import java.util.Set;

import net.jk.util.page.PaginationSupport;

import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Projections;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

/**
 * Hibernate资源库的具体实现,可用作每个实体的最基础的资源库
 * 
 * @author cjk
 * @version 1.000 2008-11-23
 */
public class GenericHibernateDao<T> extends HibernateDaoSupport implements
		HibernateRepository<T> {
	protected final Logger log = LogManager.getLogger(getClass());
	private Class<T> persistentClass;

	public GenericHibernateDao(Class<T> persistentClass) {
		this.persistentClass = persistentClass;
	}

	/*
	 * @see net.jk.common.dao.GenericDao#clearAll()
	 */
	public int clearAll() {
		final String entryName = persistentClass.getName();
		return ((Integer) super.getHibernateTemplate().execute(
				new HibernateCallback() {

					public Object doInHibernate(Session session)
							throws HibernateException, SQLException {
						String deleteHQL = "delete " + entryName;
						return session.createQuery(deleteHQL).executeUpdate();
					}

				})).intValue();
	}

	/*
	 * @see net.jk.common.dao.GenericDao#delete(java.lang.Object)
	 */
	public void delete(Object persistentObject) {
		super.getHibernateTemplate().delete(persistentObject);
	}

	/*
	 * @see net.jk.common.dao.GenericDao#deleteAll(java.util.Collection)
	 */
	public void deleteAll(Collection<T> collections) {
		super.getHibernateTemplate().deleteAll(collections);
	}

	/*
	 * @see net.jk.common.dao.GenericDao#deleteById(java.io.Serializable)
	 */
	public void deleteById(String id) {
		super.getHibernateTemplate().delete(this.get(id));
	}

	/*
	 * @see net.jk.common.dao.GenericDao#deleteByIdSet(java.util.Set)
	 */
	public int deleteByIdSet(final Set<String> idSet) {
		final String entryName = persistentClass.getName();
		return ((Integer) super.getHibernateTemplate().execute(
				new HibernateCallback() {

					public Object doInHibernate(Session session)
							throws HibernateException, SQLException {
						int i = 0;
						String deleteHQL = "delete " + entryName
								+ " where id=:id";
						for (String id : idSet) {
							session.createQuery(deleteHQL).setSerializable(
									"id", id).executeUpdate();
							i++;
						}
						return i;
					}

				})).intValue();
	}

	/*
	 * @see
	 * net.jk.common.dao.GenericDao#findAllByCriteria(org.hibernate.criterion
	 * .DetachedCriteria)
	 */
	@SuppressWarnings("unchecked")
	public List<T> findAllByCriteria(final DetachedCriteria detachedCriteria) {
		return (List<T>) getHibernateTemplate().execute(
				new HibernateCallback() {
					public Object doInHibernate(Session session)
							throws HibernateException {
						Criteria criteria = detachedCriteria
								.getExecutableCriteria(session);
						return criteria.list();
					}
				});
	}

	/*
	 * @see
	 * net.jk.common.dao.GenericDao#findPageByCriteria(org.hibernate.criterion
	 * .DetachedCriteria)
	 */
	public PaginationSupport<T> findPageByCriteria(
			DetachedCriteria detachedCriteria) {
		return findPageByCriteria(detachedCriteria, PaginationSupport.PAGESIZE,
				0);
	}

	/*
	 * @see
	 * net.jk.common.dao.GenericDao#findPageByCriteria(org.hibernate.criterion
	 * .DetachedCriteria, int)
	 */
	public PaginationSupport<T> findPageByCriteria(
			DetachedCriteria detachedCriteria, int startIndex) {
		return findPageByCriteria(detachedCriteria, PaginationSupport.PAGESIZE,
				startIndex);
	}

	/*
	 * @see
	 * net.jk.common.dao.GenericDao#findPageByCriteria(org.hibernate.criterion
	 * .DetachedCriteria, int, int)
	 */
	@SuppressWarnings("unchecked")
	public PaginationSupport<T> findPageByCriteria(
			final DetachedCriteria detachedCriteria, final int pageSize,
			final int startIndex) {
		return (PaginationSupport) getHibernateTemplate().execute(
				new HibernateCallback() {
					public Object doInHibernate(Session session)
							throws HibernateException {
						Criteria criteria = detachedCriteria
								.getExecutableCriteria(session);
						int totalCount = ((Integer) criteria.setProjection(
								Projections.rowCount()).uniqueResult())
								.intValue();
						criteria.setProjection(null);
						List items = criteria.setFirstResult(startIndex)
								.setMaxResults(pageSize).list();
						PaginationSupport ps = new PaginationSupport(items,
								totalCount, pageSize, startIndex);
						return ps;
					}
				});
	}

	/*
	 * @see net.jk.common.dao.GenericDao#get(java.io.Serializable)
	 */
	@SuppressWarnings("unchecked")
	public T get(String id) {
		T entity = (T) super.getHibernateTemplate().get(this.persistentClass,
				id);

		if (entity == null) {
			log.warn("Uh oh, '" + this.persistentClass + "' object with id '"
					+ id + "' not found...");
			return null;
		}

		return entity;
	}

	/*
	 * @see net.jk.common.dao.GenericDao#getAll()
	 */
	@SuppressWarnings("unchecked")
	public List<T> getAll() {
		return super.getHibernateTemplate().loadAll(this.persistentClass);
	}

	/*
	 * @see
	 * net.jk.common.dao.GenericDao#getCountByCriteria(org.hibernate.criterion
	 * .DetachedCriteria)
	 */
	public int getCountByCriteria(final DetachedCriteria detachedCriteria) {
		Integer count = (Integer) getHibernateTemplate().execute(
				new HibernateCallback() {
					public Object doInHibernate(Session session)
							throws HibernateException {
						Criteria criteria = detachedCriteria
								.getExecutableCriteria(session);
						return criteria.setProjection(Projections.rowCount())
								.uniqueResult();
					}
				});
		return count.intValue();
	}

	public SessionFactory getMySessionFactory() {
		return getSessionFactory();
	}

	/*
	 * @see net.jk.common.dao.GenericDao#save(java.lang.Object)
	 */
	public T save(T newInstance) {
		super.getHibernateTemplate().persist(newInstance);
		return newInstance;
	}

	public void saveOrUpdate(T newInstance) {
		getHibernateTemplate().saveOrUpdate(newInstance);
	}

	@Autowired
	public void setMySessionFactory(SessionFactory mySessionFactory) {
		setSessionFactory(mySessionFactory);
	}

	/*
	 * @see net.jk.common.dao.GenericDao#update(java.lang.Object)
	 */
	public void update(Object transientObject) {
		super.getHibernateTemplate().update(transientObject);
	}

	public HibernateTemplate getHibTpl() {
		return getHibernateTemplate();
	}
}
